#include "Precomp.h"
#include "ltGame.h"
#include "ltGraphicManager.h"
#include "ltInputManager.h"
#include "ltMapFactory.h"
#include "ltGUIHelper.h"
#include <boost/bind.hpp>

namespace Lotus
{
	LT_IMPLEMENT_SINGLETON(Game);

	Game::Game()
		:pause(false)
	{
		//! Create log
		Log = new Utilities::Log("logs/Game.log");
	}

	bool Game::init()
	{
		//! Init graphic manager
		if(!initGraphicManager())
		{
			log() << "Error: Failed to initialise Graphic manager";
			return false;
		}
		log() << "Graphic manager Initialised";

		//! Init input manager
		if(!initInputManager())
		{
			log() << "Error: Failed to initialise Input manager";
			return false;
		}
		log() << "Input manager Initialised";

		if(!initGUI())
		{
			log() << "Error: Failed to initialise GUI";
			return false;
		}
		log()<< "GUI initialised";
		
		//! Init state manager
		if(!initMapFactory())
		{
			log() << "Error: Failed to initialise Map factory";
			return false;
		}
		log() << "Map factory Initialised";

		log() << "*-*-* All manager Initialised *-*-*";
		log() << "***************************************";
		log() << "Lotus Game";
		log() << "Version " << LOTUS_VERSION << "(" << LOTUS_VERSION_NAME << ")";
		log() << "***************************************";
		return true;
	}

	void Game::run()
	{
		//! Begin loop
		log() << "Game loop begin";
		currentState=getInitialState();
		frameEvent=GraphicManager::getInstance().FrameStartedEvent.connect(boost::bind(&Game::update,this,_1));
		currentState->onEnter();
		GUIHelper::getInstance().getGui()->setSceneManager(currentState->getSceneManager());
		GraphicManager::getInstance().getOgreRoot()->startRendering();
		GUIHelper::getInstance().getGui()->setSceneManager(NULL);
		currentState->onLeave();
		log() << "Game loop end";
	}

	void Game::setPaused(bool _pause)
	{
		if(!pause&&_pause)//turn on
		{
			frameEvent.disconnect();
			log()<<"Game paused";
		}
		if(pause&&!_pause)//turn off
		{
			frameEvent=GraphicManager::getInstance().FrameStartedEvent.connect(boost::bind(&Game::update,this,_1));
			log()<<"Game resumed";
		}
		pause=_pause;
	}

	bool Game::isPaused() const
	{
		return pause;
	}

	void Game::changeState(IGameState* newState)
	{
		currentState->onLeave();
		currentState=newState;
		currentState->onEnter();
		GUIHelper::getInstance().getGui()->setSceneManager(currentState->getSceneManager());
	}

	void Game::changeMap(const char* newMap)
	{
		currentState->onLeave();
		log()<<"Loading map "<<newMap;
		currentState=MapFactoryBase::getInstance().createMapFromFile(newMap);
		log()<<"Enter map "<<newMap;
		currentState->onEnter();
		GUIHelper::getInstance().getGui()->setSceneManager(currentState->getSceneManager());
	}

	IGameState* Game::getCurrentState() const
	{
		return currentState;
	}

	Utilities::Log& Game::log() const
	{
		return *Log;
	}

	void Game::shutdown()
	{
		GraphicManager::getInstance().stopRendering();
	}

	void Game::update(const Ogre::FrameEvent& ev)
	{
		currentState->update(ev.timeSinceLastFrame);
	}

	Game::~Game()
	{
		log() << "*-*-* Game shutdown *-*-*";
		log() <<"Average FPS: "<<GraphicManager::getInstance().getOgreRenderWindow()->getAverageFPS();
		log() <<"Best FPS: "<< GraphicManager::getInstance().getOgreRenderWindow()->getBestFPS();
		log() <<"Worst FPS: "<< GraphicManager::getInstance().getOgreRenderWindow()->getWorstFPS();
		
		//! Destroy all manager
		delete MapFactoryBase::getInstancePtr();
		log() << "Map factory destroyed";

		delete GUIHelper::getInstancePtr();
		log() << "GUI destroyed";

		delete InputManager::getInstancePtr();
		log() << "Input manager destroyed";

		delete GraphicManager::getInstancePtr();
		log() << "Graphic manager destroyed";

		//! Destroy log
		log() << "Bye bye";	
		delete Log;
	}

	bool Game::initGraphicManager()
	{
		new GraphicManager;
		return GraphicManager::getInstance().init("Lotus engine");
	}

	bool Game::initInputManager()
	{
		new InputManager;
		return InputManager::getInstance().init(*GraphicManager::getInstance().getOgreRenderWindow());
	}

	bool Game::initMapFactory()
	{
		new MapFactory<>;//default type
		return true;
	}

	bool Game::initGUI()
	{
		new GUIHelper();
		return true;
	}

}